/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @addtogroup Web
 * @{
 *
 * @brief 提供ArkWeb在Native侧的能力，如网页刷新、执行JavaScript、注册回调等。
 * @since 12
 */
/**
 * @file arkweb_type.h
 *
 * @brief 提供ArkWeb在Native侧的公共类型定义。
 * @kit ArkWeb
 * @include <web/arkweb_type.h>
 * @library libohweb.so
 * @syscap SystemCapability.Web.Webview.Core
 * @since 12
 */

#ifndef ARKWEB_TYPE_H
#define ARKWEB_TYPE_H

#include <stddef.h>
#include <stdint.h>

#include "arkweb_error_code.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief 定义JavaScript Bridge数据的基础结构。
 *
 * @since 12
 */
typedef struct {
    /** 指向传输数据的指针。仅支持前端传入String和ArrayBuffer类型，其余类型会被json序列化后，以String类型传递。 */
    const uint8_t* buffer;
    /** 传输数据的长度。 */
    size_t size;
} ArkWeb_JavaScriptBridgeData;

/**
 * @brief Post Message数据类型。
 *
 * @since 12
 */
typedef enum ArkWeb_WebMessageType {
    /** 错误数据。 */
    ARKWEB_NONE = 0,
    /** 字符串数据类型。 */
    ARKWEB_STRING,
    /** 字节流数据类型。 */
    ARKWEB_BUFFER
} ArkWeb_WebMessageType;

/**
 * @brief JavaScript数据类型。
 *
 * @since 18
 */
typedef enum ArkWeb_JavaScriptValueType {
    /** 错误数据。 */
    ARKWEB_JAVASCRIPT_NONE = 0,
    /** 字符串数据类型。 */
    ARKWEB_JAVASCRIPT_STRING,
    /** bool数据类型。 */
    ARKWEB_JAVASCRIPT_BOOL
} ArkWeb_JavaScriptValueType;

/**
 * @brief Post Message数据结构体指针。
 *
 * @since 12
 */
typedef struct ArkWeb_WebMessage* ArkWeb_WebMessagePtr;

/**
 * @brief JavaScript数据结构体指针。
 *
 * @since 18
 */
typedef struct ArkWeb_JavaScriptValue* ArkWeb_JavaScriptValuePtr;

/**
 * @brief 注入的JavaScript执行完成的回调。
 *
 * @param webTag Web组件名称。
 * @param data JavaScriptBridge数据。
 * @param userData 用户自定义的数据。
 *
 * @since 12
 */
typedef void (*ArkWeb_OnJavaScriptCallback)(
    const char* webTag, const ArkWeb_JavaScriptBridgeData* data, void* userData);

/**
 * @brief Proxy方法被执行的回调。
 *
 * @param webTag Web组件名称。
 * @param dataArray 数组数据。
 * @param arraySize 数组大小。
 * @param userData 用户自定义的数据。
 *
 * @since 12
 */
typedef void (*ArkWeb_OnJavaScriptProxyCallback)(
    const char* webTag, const ArkWeb_JavaScriptBridgeData* dataArray, size_t arraySize, void* userData);

/**
 * @brief Proxy方法被执行的回调。
 *
 * @param webTag Web组件名称。
 * @param dataArray 数组数据。
 * @param arraySize 数组大小。
 * @param userData 用户自定义的数据。
 *
 * @since 18
 */
typedef ArkWeb_JavaScriptValuePtr (*ArkWeb_OnJavaScriptProxyCallbackWithResult)(
    const char* webTag, const ArkWeb_JavaScriptBridgeData* dataArray, size_t arraySize, void* userData);

/**
 * @brief 组件事件通知相关的通用回调。
 *
 * @param webTag Web组件名称。
 * @param userData 用户自定义的数据。
 *
 * @since 12
 */
typedef void (*ArkWeb_OnComponentCallback)(const char* webTag, void* userData);

/**
 * @brief 滚动事件回调。
 *
 * @param webTag Web组件名称。
 * @param userData 用户自定义的数据。
 * @param x X轴滚动偏移。
 * @param y Y轴滚动偏移。
 *
 * @since 18
 */
typedef void (*ArkWeb_OnScrollCallback)(const char* webTag, void* userData, double x, double y);

/**
 * @brief Post Message端口结构体指针。
 *
 * @since 12
 */
typedef struct ArkWeb_WebMessagePort* ArkWeb_WebMessagePortPtr;

/**
 * @brief 处理HTML发送过来的Post Message数据。
 *
 * @param webTag Web组件名称。
 * @param port Post Message端口。
 * @param message Post Message数据。
 * @param userData 用户自定义数据。
 *
 * @since 12
 */
typedef void (*ArkWeb_OnMessageEventHandler)(
    const char* webTag, const ArkWeb_WebMessagePortPtr port, const ArkWeb_WebMessagePtr message, void* userData);

/**
 * @brief 注入的JavaScript结构体。
 *
 * @since 12
 */
typedef struct {
    /** 注入的JavaScript代码。 */
    const uint8_t* buffer;
    /** JavaScript代码长度。 */
    size_t size;
    /** JavaScript执行完成的回调。 */
    ArkWeb_OnJavaScriptCallback callback;
    /** 需要在回调中携带的自定义数据。 */
    void* userData;
} ArkWeb_JavaScriptObject;

/**
 * @brief 注入的Proxy方法通用结构体。
 *
 * @since 12
 */
typedef struct {
    /** 注入的方法名。 */
    const char* methodName;
    /** Proxy方法执行的回调。 */
    ArkWeb_OnJavaScriptProxyCallback callback;
    /** 需要在回调中携带的自定义数据。 */
    void* userData;
} ArkWeb_ProxyMethod;

/**
 * @brief 注入的Proxy方法通用结构体。
 *
 * @since 18
 */
typedef struct {
    /** 注入的方法名。 */
    const char* methodName;
    /** Proxy方法执行的回调。 */
    ArkWeb_OnJavaScriptProxyCallbackWithResult callback;
    /** 需要在回调中携带的自定义数据。 */
    void* userData;
} ArkWeb_ProxyMethodWithResult;

/**
 * @brief 注入的Proxy对象通用结构体。
 *
 * @since 12
 */
typedef struct {
    /** 注入的对象名。 */
    const char* objName;
    /** 注入的对象携带的方法结构体数组。 */
    const ArkWeb_ProxyMethod* methodList;
    /** 方法结构体数组的长度。 */
    size_t size;
} ArkWeb_ProxyObject;

/**
 * @brief 注入的Proxy对象通用结构体。
 *
 * @since 18
 */
typedef struct {
    /** 注入的对象名。 */
    const char* objName;
    /** 注入的对象携带的方法结构体数组。 */
    const ArkWeb_ProxyMethodWithResult* methodList;
    /** 方法结构体数组的长度。 */
    size_t size;
} ArkWeb_ProxyObjectWithResult;

/**
 * @brief Controller相关的Native API结构体。
 * 在调用接口前建议通过ARKWEB_MEMBER_MISSING校验该函数结构体是否有对应函数指针，避免SDK与设备ROM不匹配导致crash问题。
 *
 * @since 12
 */
typedef struct {
    /** 结构体的大小。 */
    size_t size;
    /**
     * @brief 注入JavaScript脚本。
     *
     *
     * @param webTag Web组件名称。
     * @param javascriptObject 注入的JavaScript对象。
     */
    void (*runJavaScript)(const char* webTag, const ArkWeb_JavaScriptObject* javascriptObject);
    /**
     * @brief 注入JavaScript对象到window对象中，并在window对象中调用该对象的同步方法。
     *
     *
     * @param webTag Web组件名称。
     * @param proxyObject 注册的对象。
     */
    void (*registerJavaScriptProxy)(const char* webTag, const ArkWeb_ProxyObject* proxyObject);
    /**
     * @brief 删除通过registerJavaScriptProxy注册到window上的指定name的应用侧JavaScript对象。
     *
     *
     * @param webTag Web组件名称。
     * @param objName JavaScript对象名称。
     */
    void (*deleteJavaScriptRegister)(const char* webTag, const char* objName);
    /**
     * @brief 刷新当前网页。
     *
     *
     * @param webTag Web组件名称。
     */
    void (*refresh)(const char* webTag);
    /**
     * @brief 注入JavaScript对象到window对象中，并在window对象中调用该对象的异步方法。
     *
     *
     * @param webTag Web组件名称。
     * @param proxyObject 注册的对象。
     */
    void (*registerAsyncJavaScriptProxy)(const char* webTag, const ArkWeb_ProxyObject* proxyObject);
    /**
     * @brief 创建Post Message端口。
     *
     *
     * @param webTag Web组件名称。
     * @param size 出参，端口数量。
     * @return Post Message端口结构体指针。
     */
    ArkWeb_WebMessagePortPtr* (*createWebMessagePorts)(const char* webTag, size_t* size);

    /**
     * @brief 销毁端口。
     *
     * @param ports 发送Message端口结构体指针数组。
     * @param size 端口数量。
     */
    void (*destroyWebMessagePorts)(ArkWeb_WebMessagePortPtr** ports, size_t size);

    /**
     * @brief 将端口发送到HTML主页面.
     *
     * @param webTag Web组件名称。
     * @param name 发送给HTML的消息名称。
     * @param webMessagePorts Post Message端口结构体指针。
     * @param size 端口数量。
     * @param url 接收到消息的页面url。
     * @return 返回值错误码。
     *         {@link ARKWEB_SUCCESS} 执行成功。
     *         {@link ARKWEB_INVALID_PARAM} 参数无效。
     *         {@link ARKWEB_INIT_ERROR} 初始化失败，没有找到与webTag绑定的Web组件。
     */
    ArkWeb_ErrorCode (*postWebMessage)(
        const char* webTag, const char* name, ArkWeb_WebMessagePortPtr* webMessagePorts, size_t size, const char* url);

    /**
     * @brief 获取调用JavaScriptProxy最后一帧的url。
     *        在JavaScriptProxy调用的线程上调用。
     *        通过registerJavaScriptProxy或者javaScriptProxy注入JavaScript对象到window对象中。该接口可以获取最后一次调用注入对象frame的url。
     *        在被调用函数内部获取url才能获取到正确值，可以在函数里内部获取url后保存下来。
     * @return 调用JavaScriptProxy最后一帧的url。
     * @since 14
     */
    const char* (*getLastJavascriptProxyCallingFrameUrl)();

    /**
     * @brief 注入JavaScript对象到window对象中，并在window对象中调用该对象的同步方法。该对象的同步方法可以带返回值。
     *
     * @param webTag Web组件名称。
     * @param proxyObject 注册的对象。
     * @param permission json格式字符串，默认值为空。该字符串用来配置JSBridge的权限限制，可以配置对象和方法级别。
     *
     * @since 18
     */
    void (*registerJavaScriptProxyEx)(const char* webTag, const ArkWeb_ProxyObjectWithResult* proxyObject,
        const char* permission);

    /**
     * @brief 注入JavaScript对象到window对象中，并在window对象中调用该对象的异步方法。
     *
     * @param webTag Web组件名称。
     * @param proxyObject 注册的对象。
     * @param permission json格式字符串，默认值为空。该字符串用来配置JSBridge的权限限制，可以配置对象和方法级别。
     *
     * @since 18
     */
    void (*registerAsyncJavaScriptProxyEx)(const char* webTag, const ArkWeb_ProxyObject* proxyObject,
        const char* permission);
} ArkWeb_ControllerAPI;

/**
 * @brief Component相关的Native API结构体。
 *
 * @since 12
 */
typedef struct {
    /** 结构体的大小。 */
    size_t size;
    /**
     * @brief 当Controller成功绑定到Web组件时触发该回调。
     * 
     * @param webTag Web组件名称。
     * @param callback onControllerAttached的回调函数。
     * @param userData 用户自定义数据。
     * 
     * @since 12
     */
    void (*onControllerAttached)(const char* webTag, ArkWeb_OnComponentCallback callback, void* userData);
    /**
     * @brief 网页开始加载时触发该回调，且只在主frame触发，iframe或者frameset的内容加载时不会触发此回调。
     * 
     * @param webTag Web组件名称。
     * @param callback onPageBegin的回调函数。
     * @param userData 用户自定义数据。
     * 
     * @since 12
     */
    void (*onPageBegin)(const char* webTag, ArkWeb_OnComponentCallback callback, void* userData);
    /**
     * @brief 网页加载完成时触发该回调，且只在主frame触发。
     * 
     * @param webTag Web组件名称。
     * @param callback onPageEnd的回调函数。
     * @param userData 用户自定义数据。
     * 
     * @since 12
     */
    void (*onPageEnd)(const char* webTag, ArkWeb_OnComponentCallback callback, void* userData);
    /**
     * @brief 当前Web组件销毁时触发该回调。
     * 
     * @param webTag Web组件名称。
     * @param callback onDestroy的回调函数。
     * @param userData 用户自定义数据。
     * 
     * @since 12
     */
    void (*onDestroy)(const char* webTag, ArkWeb_OnComponentCallback callback, void* userData);
} ArkWeb_ComponentAPI;

/**
 * @brief Post Message相关的Native API结构体。
 * 在调用接口前建议通过ARKWEB_MEMBER_MISSING校验该函数结构体是否有对应函数指针，避免SDK与设备ROM不匹配导致crash问题。
 *
 * @since 12
 */
typedef struct {
    /** 结构体的大小。*/
    size_t size;
    /**
     * @brief 发送消息到HTML。
     *
     * @param webMessagePort Post Message端口结构体指针。
     * @param webTag Web组件名称。
     * @param webMessage 需要发送的消息。
     * @return 返回值错误码。
     *         {@link ARKWEB_SUCCESS} 执行成功。
     *         {@link ARKWEB_INVALID_PARAM} 参数无效。
     *         {@link ARKWEB_INIT_ERROR} 初始化失败，没有找到与webTag绑定的Web组件。
     */
    ArkWeb_ErrorCode (*postMessage)(
        const ArkWeb_WebMessagePortPtr webMessagePort, const char* webTag, const ArkWeb_WebMessagePtr webMessage);
    /**
     * @brief 关闭消息端口。
     *
     * @param webMessagePort Post Message端口结构体指针。
     * @param webTag Web组件名称。
     */
    void (*close)(const ArkWeb_WebMessagePortPtr webMessagePort, const char* webTag);
    /**
     * @brief 设置接收HTML消息的回调。
     *
     * @param webMessagePort Post Message端口结构体指针。
     * @param webTag Web组件名称。
     * @param messageEventHandler 处理消息的回调。
     * @param userData 用户自定义数据。
     */
    void (*setMessageEventHandler)(const ArkWeb_WebMessagePortPtr webMessagePort, const char* webTag,
        ArkWeb_OnMessageEventHandler messageEventHandler, void* userData);
} ArkWeb_WebMessagePortAPI;

/**
 * @brief Post Message数据相关的Native API结构体。
 * 在调用接口前建议通过ARKWEB_MEMBER_MISSING校验该函数结构体是否有对应函数指针，避免SDK与设备ROM不匹配导致crash问题。
 *
 * @since 12
 */
typedef struct {
    /** 结构体的大小。*/
    size_t size;
    /**
     *  @brief 创建消息。
     *
     *  @return 消息结构体。
     */
    ArkWeb_WebMessagePtr (*createWebMessage)();
    /**
     *  @brief 销毁消息。
     *
     *  @param webMessage 需要销毁的消息。
     */
    void (*destroyWebMessage)(ArkWeb_WebMessagePtr* webMessage);
    /**
     *  @brief 设置消息类型。
     *
     *  @param webMessage 消息结构体指针。
     *  @param type 消息类型。
     */
    void (*setType)(ArkWeb_WebMessagePtr webMessage, ArkWeb_WebMessageType type);
    /**
     *  @brief 获取消息类型。
     *
     *  @param webMessage 消息结构体指针。
     *  @return 消息类型。
     */
    ArkWeb_WebMessageType (*getType)(ArkWeb_WebMessagePtr webMessage);
    /**
     *  @brief 设置数据。
     *
     *  @param webMessage 消息结构体指针。
     *  @param data 数据指针。
     *  @param dataLength 数据长度。
     */
    void (*setData)(ArkWeb_WebMessagePtr webMessage, void* data, size_t dataLength);
    /**
     *  @brief 获取数据。
     *
     *  @param webMessage 消息结构体指针。
     *  @param dataLength 出参，数据长度。
     *  @return 数据指针。
     */
    void* (*getData)(ArkWeb_WebMessagePtr webMessage, size_t* dataLength);
} ArkWeb_WebMessageAPI;

/**
 * @brief 定义了ArkWeb的CookieManager接口。
 * 在调用接口之前，建议使用ARKWEB_MEMBER_MISSING检查函数结构体是否有对应的函数指针，避免SDK与设备ROM不匹配导致崩溃。
 *
 * @since 12
 */
typedef struct {
    /** 结构体的大小。*/
    size_t size;

    /**
     * @brief 获取指定URL对应的cookie值。
     *
     * @param url 要获取的cookie所属的URL，建议使用完整的URL。
     * @param incognito true表示获取隐私模式下webview的内存cookie, false表示获取非隐私模式下的cookie。
     * @param includeHttpOnly 如果为true，则标记为HTTP-Only属性的cookie也将包含在cookieValue中。
     * @param cookieValue  获取与URL对应的cookie值。
     * @return 返回值错误码。
     *         {@link ARKWEB_SUCCESS} 获取cookie成功。
     *         {@link ARKWEB_INVALID_URL} 设置的URL无效。
     *         {@link ARKWEB_INVALID_PARAM} cookieValue参数无效。
     */
    ArkWeb_ErrorCode (*fetchCookieSync)(const char* url, bool incognito, bool includeHttpOnly, char** cookieValue);

    /**
     * @brief 设置指定URL的cookie值。
     *
     * @param url 指定cookie所属的URL，建议填写完整的URL。
     * @param cookieValue 要设置的cookie的值。
     * @param incognito true表示在隐私模式下设置对应URL的Cookie，false表示以非隐私模式设置对应URL的cookie。
     * @param includeHttpOnly 如果为true，则标记为HTTP-Only的cookie也可以被覆盖。
     * @return 返回值错误码。
     *         {@link ARKWEB_SUCCESS} 设置cookie成功。
     *         {@link ARKWEB_INVALID_URL} 设置的URL无效。
     *         {@link ARKWEB_INVALID_COOKIE_VALUE} cookieValue参数无效。
     */
    ArkWeb_ErrorCode (*configCookieSync)(const char* url,
        const char* cookieValue, bool incognito, bool includeHttpOnly);

    /**
     * @brief 检查Cookie是否存在。
     *
     * @param incognito true表示隐私模式下是否存在cookie，false表示非隐私模式下是否存在cookie。
     * @return true表示cookie存在，false表示cookie不存在。
     */
    bool (*existCookies)(bool incognito);

    /**
     * @brief 清除所有cookies。
     *
     * @param incognito true表示清除隐私模式下的所有cookies，false表示清除非隐私模式下的所有cookies。
     */
    void (*clearAllCookiesSync)(bool incognito);

    /**
     * @brief 清除所有会话Cookies。
     */
    void (*clearSessionCookiesSync)();
} ArkWeb_CookieManagerAPI;

/**
 * @brief 定义了ArkWeb的JavaScriptValue接口。
 * 在调用接口之前，建议使用ARKWEB_MEMBER_MISSING检查函数结构体是否有对应的函数指针，避免SDK与设备ROM不匹配导致崩溃。
 *
 * @since 18
 */
typedef struct {
    /** 结构体的大小。*/
    size_t size;

    /**
     * @brief 创建一个JavaScript值，用于返回给HTML。
     *
     * @param type JavaScript值的类型。
     * @param data JavaScript值的数据缓冲区。
     * @param dataLength JavaScript值的缓冲区大小。
     * @return 创建出来的JavaScript值。
     */
    ArkWeb_JavaScriptValuePtr (*createJavaScriptValue)(ArkWeb_JavaScriptValueType type, void* data, size_t dataLength);
} ArkWeb_JavaScriptValueAPI;

/**
 * @brief 检查结构体中是否存在该成员变量。
 *
 * @since 12
 */
#define ARKWEB_MEMBER_EXISTS(s, f) \
    ((intptr_t) & ((s)->f) - (intptr_t)(s) + sizeof((s)->f) <= *reinterpret_cast<size_t*>(s))

/**
 * @brief 当前结构体存在该成员变量则返回false，否则返回true。
 *
 * @since 12
 */
#define ARKWEB_MEMBER_MISSING(s, f) (!ARKWEB_MEMBER_EXISTS(s, f) || !((s)->f))

#ifdef __cplusplus
}
#endif
#endif // ARKWEB_TYPE_H
/** @} */